<?php
class AnnounceController extends BaseController
{
    private $bt_encode;
    private $bt_decode;
    public function __construct($uri)
    {
        parent::__construct($uri);
        $this->bt_encode = new File_Bittorrent2_Encode();
        $this->bt_decode = new File_Bittorrent2_Decode();
    }

    /**
     * @todo 屏蔽迅雷等误报上传量的客户端
     * 是否允许：一个用户下载同一个种子时用同一个peer_id时有多个ip，比如双线。
     * 答：允许。返回peers时滤掉本人的所有ip
     * 是否允许：一个用户下载同一个种子时用不同的peer_id，比如相同ip情况1可能是自己开2个软件刷分，不同ip情况2可能是双线刷分，情况3家里开着做种，在朋友家下载，相当于多人共用一个帐号。返回peers时滤掉本人的所有ip，所以这样不会刷分，但用户可能手动在bt软件中添加对方，导致可以连上刷分。
     * 答：不允许。
     * 是否允许：一个用户下载不同的种子使用不同的peer_id，比如相同ip情况1用ut下载，然后用deluge下载另一个文件。不同ip情况2比如双线。情况3共用帐号，我下载这个，别人下载别的。
     * 答：允许。
     * 如果用户开启了IPv6隧道，utorrent会传递ipv6参数。这时用户用的可能还是ipv4网络，如何处理？但用户的ipv6可能也是有效的。暂不处理：因为如果用户是首选ipv6网络，http请求本站时就是ipv6。首选ipv4时，是否有必要记录ipv6，待开发。
     * http://www.ipv6home.cn/html/84/t-11084.html
     */
    private function checkClient()
    {
        //检查user agent
        $blacklist = ConfLib::get('blacklist', 'user_agent');
        if(in_array($_SERVER['HTTP_USER_AGENT'], $blacklist)) { //这是 遍历查找，时间复杂度太高。todo
            throw new HttpException(403);
        }
        //检查peer_id
    }
    
    /**
     * http://wiki.theory.org/BitTorrentSpecification#Tracker_Request_Parameters
     * http://www.cnblogs.com/MaxWoods/archive/2009/07/25/1530851.html
     */
    private function get($passkey='')
    {
        $this->checkClient();
        $params = array('info_hash', 'peer_id', 'port', 'uploaded', 'downloaded', 'left');
        if(empty($passkey)) {
            $params[] = 'passkey';
        } else {
            $this->input['passkey'] = $passkey;
        }
        $this->checkParams($params);
        $data = $this->input;
        if((!isset($data['ip'])) || empty($data['ip'])) {
            $data['ip'] = $_SERVER['REMOTE_ADDR'];
        }

        $user_model = new UserModel();
        $data['user_id'] = $user_model->getUserIdByPasskey($data['passkey']);
        //todo 反作弊
        $data['id'] = $data['peer_id'];
        $data['info_hash'] = rawurldecode($data['info_hash']);

        $m = new PeerModel();
        $m->set($data);
        //如果用户的ip和ipv6不同，说明是优先ipv4，所以都要记录
        if((isset($data['ipv6'])) && (!empty($data['ipv6'])) && ($data['ip']!==$data['ipv6'])) {
            //todo ipv6格式检查
            //$data['ip'] = $data['ipv6'];
            //$m->set($data);
        }
        $delete_peer_ids = array($data['peer_id']); //todo 排除自己 方案1排除自己的peer_id，方案2排除自己的user_id，应该用后者，因为用户在多个地点下载刷分时peer_id不同。
        $no_peer_id = false;
        if((isset($data['compact']) && $data['compact']==1) || (isset($data['no_peer_id']) && $data['no_peer_id']==1)) {
            $no_peer_id = true;
        }
        $r = $m->getPeers($data['info_hash'], $no_peer_id, $delete_peer_ids);
        $this->output['http']['content-type'] = 'text/plain';
        $data = array();
        $data['interval'] = 120;
        $data['min interval'] = 120;
        $data['complete'] = $r['complete'];
        $data['incomplete'] = $r['incomplete'];
        $data['peers'] = $r['peers'];
        $this->output['data'] = $this->bt_encode->encode($data);
        return $this->output;
    }

    public function route()
    {
        if(1 === preg_match('/^\/announce$/', $this->uri)) {
            switch($this->http_method) {
                case 'get' :
                    return $this->get();
                    break;
            }
        }
        if(1 === preg_match('/^\/announce\/[0-9a-z]{32}$/', $this->uri)) {
            switch($this->http_method) {
                case 'get' :
                    $tmp = explode('/', $this->uri);
                    return $this->get($tmp[2]);
                    break;
            }
        }
        throw new ControllerException();
    }
}
?>
